package org.xiaov.framework.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.mail.MailAccount;
import cn.hutool.extra.mail.MailUtil;
import org.springframework.boot.autoconfigure.mail.MailProperties;
import org.springframework.util.ResourceUtils;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.FileTemplateResolver;
import org.xiaov.framework.component.SpringContext;
import org.xiaov.framework.constant.Constant;
import org.xiaov.framework.exception.BizException;


import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 描述：扩展hutool的邮件工具类
 * </p>
 *
 * @author xiaovcloud
 * @since 2021/12/1 22:19
 */
public class EmailUtils extends MailUtil {
    /**
     * 全局的邮件对象
     */
    private static final MailAccount MAIL_ACCOUNT = init();

    /**
     * 初始化方法
     *
     * @return MailAccount
     */
    public static MailAccount init() {
        MailProperties mailProperties = SpringContext.getBean(MailProperties.class);
        mailProperties.getPassword();
        mailProperties.getProperties();
        mailProperties.getHost();
        mailProperties.getPort();
        mailProperties.getProtocol();
        mailProperties.getDefaultEncoding();
        MailAccount mailAccount = new MailAccount();
        mailAccount.setUser(mailProperties.getUsername())
                .setPass(mailProperties.getPassword())
                .setHost(mailProperties.getHost())
                .setPort(mailProperties.getPort())
                .setFrom(mailProperties.getUsername())
                .setCharset(mailProperties.getDefaultEncoding());
        return mailAccount;
    }

    /**
     * 使用配置文件中设置的账户发送模板邮件，发送给单个或多个收件人<br>
     * 多个收件人可以使用逗号“,”分隔，也可以通过分号“;”分隔
     *
     * @param to           收件人
     * @param subject      标题
     * @param templatePath 模板地址
     * @param params       模板中的参数
     * @param files        附件列表（可控）
     * @return message-id
     */

    public static String sendTemplate(String to,
                                      String subject,
                                      String templatePath,
                                      Map<String, Object> params,
                                      File... files) {
        FileTemplateResolver templateResolver = new FileTemplateResolver();
        templateResolver.setTemplateMode(TemplateMode.HTML);
        TemplateEngine templateEngine = new TemplateEngine();
        templateEngine.setTemplateResolver(templateResolver);
        final Context ctx = new Context();
        ctx.setVariables(params);
        LocalDateTime now = LocalDateTime.now();
        ctx.setVariable("year", now.getYear());
        ctx.setVariable("month", now.getMonthValue());
        ctx.setVariable("day", now.getDayOfMonth());

        String path;
        try {
            path = ResourceUtils.getURL("classpath:").getPath();
        } catch (FileNotFoundException e) {
            throw new BizException("找不到文件路径", e);
        }
        final String content = templateEngine.process(path + "/templates/" + templatePath, ctx);
        return sendHtml(to, subject, content, files);
    }


    /**
     * 使用配置文件中设置的账户发送文本邮件，发送给单个或多个收件人<br>
     * 多个收件人可以使用逗号“,”分隔，也可以通过分号“;”分隔
     *
     * @param to      收件人
     * @param subject 标题
     * @param content 正文
     * @param files   附件列表
     * @return message-id
     * @since 3.2.0
     */
    public static String sendText(String to,
                                  String subject,
                                  String content,
                                  File... files) {
        return send(to, subject, content, false, files);
    }

    /**
     * 使用配置文件中设置的账户发送HTML邮件，发送给单个或多个收件人<br>
     * 多个收件人可以使用逗号“,”分隔，也可以通过分号“;”分隔
     *
     * @param to      收件人
     * @param subject 标题
     * @param content 正文
     * @param files   附件列表
     * @return message-id
     * @since 3.2.0
     */
    public static String sendHtml(String to,
                                  String subject,
                                  String content,
                                  File... files) {
        return send(to, subject, content, true, files);
    }

    /**
     * 使用配置文件中设置的账户发送邮件，发送单个或多个收件人<br>
     * 多个收件人可以使用逗号“,”分隔，也可以通过分号“;”分隔
     *
     * @param to      收件人
     * @param subject 标题
     * @param content 正文
     * @param isHtml  是否为HTML
     * @param files   附件列表
     * @return message-id
     */
    public static String send(String to,
                              String subject,
                              String content,
                              boolean isHtml,
                              File... files) {
        return send(splitAddress(to), subject, content, isHtml, files);
    }

    /**
     * 使用配置文件中设置的账户发送邮件，发送单个或多个收件人<br>
     * 多个收件人、抄送人、密送人可以使用逗号“,”分隔，也可以通过分号“;”分隔
     *
     * @param to      收件人，可以使用逗号“,”分隔，也可以通过分号“;”分隔
     * @param cc      抄送人，可以使用逗号“,”分隔，也可以通过分号“;”分隔
     * @param bcc     密送人，可以使用逗号“,”分隔，也可以通过分号“;”分隔
     * @param subject 标题
     * @param content 正文
     * @param isHtml  是否为HTML
     * @param files   附件列表
     * @return message-id
     * @since 4.0.3
     */
    public static String send(String to,
                              String cc,
                              String bcc,
                              String subject,
                              String content,
                              boolean isHtml,
                              File... files) {
        return send(splitAddress(to), splitAddress(cc), splitAddress(bcc), subject, content, isHtml, files);
    }

    /**
     * 使用配置文件中设置的账户发送文本邮件，发送给多人
     *
     * @param tos     收件人列表
     * @param subject 标题
     * @param content 正文
     * @param files   附件列表
     * @return message-id
     */
    public static String sendText(Collection<String> tos,
                                  String subject,
                                  String content,
                                  File... files) {
        return send(tos, subject, content, false, files);
    }

    /**
     * 使用配置文件中设置的账户发送HTML邮件，发送给多人
     *
     * @param tos     收件人列表
     * @param subject 标题
     * @param content 正文
     * @param files   附件列表
     * @return message-id
     * @since 3.2.0
     */
    public static String sendHtml(Collection<String> tos,
                                  String subject,
                                  String content,
                                  File... files) {
        return send(tos, subject, content, true, files);
    }

    /**
     * 使用配置文件中设置的账户发送邮件，发送给多人
     *
     * @param tos     收件人列表
     * @param subject 标题
     * @param content 正文
     * @param isHtml  是否为HTML
     * @param files   附件列表
     * @return message-id
     */
    public static String send(Collection<String> tos,
                              String subject,
                              String content,
                              boolean isHtml,
                              File... files) {
        return send(tos, null, null, subject, content, isHtml, files);
    }

    /**
     * 使用配置文件中设置的账户发送邮件，发送给多人
     *
     * @param tos     收件人列表
     * @param ccs     抄送人列表，可以为null或空
     * @param bccs    密送人列表，可以为null或空
     * @param subject 标题
     * @param content 正文
     * @param isHtml  是否为HTML
     * @param files   附件列表
     * @return message-id
     * @since 4.0.3
     */
    public static String send(Collection<String> tos,
                              Collection<String> ccs,
                              Collection<String> bccs,
                              String subject,
                              String content,
                              boolean isHtml,
                              File... files) {
        return send(tos, ccs, bccs, subject, content, null, isHtml, files);
    }


    /**
     * 使用配置文件中设置的账户发送HTML邮件，发送给单个或多个收件人<br>
     * 多个收件人可以使用逗号“,”分隔，也可以通过分号“;”分隔
     *
     * @param to       收件人
     * @param subject  标题
     * @param content  正文
     * @param imageMap 图片与占位符，占位符格式为cid:$IMAGE_PLACEHOLDER
     * @param files    附件列表
     * @return message-id
     * @since 3.2.0
     */
    public static String sendHtml(String to,
                                  String subject,
                                  String content,
                                  Map<String, InputStream> imageMap,
                                  File... files) {
        return send(to, subject, content, imageMap, true, files);
    }

    /**
     * 使用配置文件中设置的账户发送邮件，发送单个或多个收件人<br>
     * 多个收件人可以使用逗号“,”分隔，也可以通过分号“;”分隔
     *
     * @param to       收件人
     * @param subject  标题
     * @param content  正文
     * @param imageMap 图片与占位符，占位符格式为cid:$IMAGE_PLACEHOLDER
     * @param isHtml   是否为HTML
     * @param files    附件列表
     * @return message-id
     */
    public static String send(String to,
                              String subject,
                              String content,
                              Map<String, InputStream> imageMap,
                              boolean isHtml,
                              File... files) {
        return send(splitAddress(to), subject, content, imageMap, isHtml, files);
    }

    /**
     * 使用配置文件中设置的账户发送邮件，发送单个或多个收件人<br>
     * 多个收件人、抄送人、密送人可以使用逗号“,”分隔，也可以通过分号“;”分隔
     *
     * @param to       收件人，可以使用逗号“,”分隔，也可以通过分号“;”分隔
     * @param cc       抄送人，可以使用逗号“,”分隔，也可以通过分号“;”分隔
     * @param bcc      密送人，可以使用逗号“,”分隔，也可以通过分号“;”分隔
     * @param subject  标题
     * @param content  正文
     * @param imageMap 图片与占位符，占位符格式为cid:$IMAGE_PLACEHOLDER
     * @param isHtml   是否为HTML
     * @param files    附件列表
     * @return message-id
     * @since 4.0.3
     */
    public static String send(String to,
                              String cc,
                              String bcc,
                              String subject,
                              String content,
                              Map<String, InputStream> imageMap,
                              boolean isHtml,
                              File... files) {
        return send(splitAddress(to), splitAddress(cc), splitAddress(bcc), subject, content, imageMap, isHtml, files);
    }

    /**
     * 使用配置文件中设置的账户发送HTML邮件，发送给多人
     *
     * @param tos      收件人列表
     * @param subject  标题
     * @param content  正文
     * @param imageMap 图片与占位符，占位符格式为cid:$IMAGE_PLACEHOLDER
     * @param files    附件列表
     * @return message-id
     * @since 3.2.0
     */
    public static String sendHtml(Collection<String> tos,
                                  String subject,
                                  String content,
                                  Map<String, InputStream> imageMap,
                                  File... files) {
        return send(tos, subject, content, imageMap, true, files);
    }

    /**
     * 使用配置文件中设置的账户发送邮件，发送给多人
     *
     * @param tos      收件人列表
     * @param subject  标题
     * @param content  正文
     * @param imageMap 图片与占位符，占位符格式为cid:$IMAGE_PLACEHOLDER
     * @param isHtml   是否为HTML
     * @param files    附件列表
     * @return message-id
     */
    public static String send(Collection<String> tos,
                              String subject,
                              String content,
                              Map<String, InputStream> imageMap,
                              boolean isHtml,
                              File... files) {
        return send(tos, null, null, subject, content, imageMap, isHtml, files);
    }

    /**
     * 使用配置文件中设置的账户发送邮件，发送给多人
     *
     * @param tos      收件人列表
     * @param ccs      抄送人列表，可以为null或空
     * @param bccs     密送人列表，可以为null或空
     * @param subject  标题
     * @param content  正文
     * @param imageMap 图片与占位符，占位符格式为cid:$IMAGE_PLACEHOLDER
     * @param isHtml   是否为HTML
     * @param files    附件列表
     * @return message-id
     * @since 4.0.3
     */
    public static String send(Collection<String> tos,
                              Collection<String> ccs,
                              Collection<String> bccs,
                              String subject,
                              String content,
                              Map<String, InputStream> imageMap,
                              boolean isHtml,
                              File... files) {
        if (MAIL_ACCOUNT.getHost() == null) {
            throw new BizException("未配置邮件发送信息");
        }
        return send(MAIL_ACCOUNT, tos, ccs, bccs, subject, content, imageMap, isHtml, files);
    }

    // ------------------------------------------------------------------------------------------------------------------------------- Custom MailAccount

    /**
     * 发送邮件给多人
     *
     * @param mailAccount 邮件认证对象
     * @param to          收件人，多个收件人逗号或者分号隔开
     * @param subject     标题
     * @param content     正文
     * @param imageMap    图片与占位符，占位符格式为cid:$IMAGE_PLACEHOLDER
     * @param isHtml      是否为HTML格式
     * @param files       附件列表
     * @return message-id
     * @since 3.2.0
     */
    public static String send(MailAccount mailAccount,
                              String to,
                              String subject,
                              String content,
                              Map<String, InputStream> imageMap,
                              boolean isHtml,
                              File... files) {
        return send(mailAccount, splitAddress(to), subject, content, imageMap, isHtml, files);
    }

    /**
     * 发送邮件给多人
     *
     * @param mailAccount 邮件帐户信息
     * @param tos         收件人列表
     * @param subject     标题
     * @param content     正文
     * @param imageMap    图片与占位符，占位符格式为cid:$IMAGE_PLACEHOLDER
     * @param isHtml      是否为HTML格式
     * @param files       附件列表
     * @return message-id
     * @since 4.6.3
     */
    public static String send(MailAccount mailAccount,
                              Collection<String> tos,
                              String subject,
                              String content,
                              Map<String, InputStream> imageMap,
                              boolean isHtml,
                              File... files) {
        return MailUtil.send(mailAccount, tos, null, null, subject, content, imageMap, isHtml, files);
    }

    /**
     * 将多个联系人转为列表，分隔符为逗号或者分号
     *
     * @param addresses 多个联系人，如果为空返回null
     * @return 联系人列表
     */
    private static List<String> splitAddress(String addresses) {
        if (StrUtil.isBlank(addresses)) {
            return null;
        }
        List<String> result;
        if (StrUtil.contains(addresses, CharUtil.COMMA)) {
            //逗号分割
            result = StrUtil.splitTrim(addresses, CharUtil.COMMA);
        } else if (StrUtil.contains(addresses, Constant.SEMICOLON)) {
            //分号分割
            result = StrUtil.splitTrim(addresses, Constant.SEMICOLON);
        } else {
            result = CollUtil.newArrayList(addresses);
        }
        return result;
    }
}
